home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / tcoop.arc / TCOOP2.ARC / BROWSE2.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-26  |  15.5 KB  |  582 lines

  1. // browse2.cpp
  2. // This program allows you to view the contents of a file.
  3. // You can display it either in ASCII or hexadecimal format.
  4. // Once a file is displayed, you can scroll through the
  5. // file using the cursor pad keys (PgUp, PgDn, and so on). To
  6. // use the program, issue the following command at the DOS
  7. // prompt:
  8. //                  browse2 <filename>
  9. //
  10. // NOTE: COMPILE THIS IN LARGE MODEL ONLY!
  11. //
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <conio.h>
  16. #include <io.h>
  17. #include <dir.h>
  18. #include <dos.h>
  19.  
  20. #define Screen (*ScreenPtr)
  21.  
  22. const long MaxBufSize = 65520L;   // Roughly 64K maximum file size
  23. const int  TabSize    = 5;        // Depends on the file
  24. const unsigned char EscKey = 27;  // Extended key codes
  25. const unsigned char PgUp   = 73;
  26. const unsigned char PgDn   = 81;
  27. const unsigned char Home   = 71;
  28. const unsigned char EndKey = 79;
  29. const unsigned char UpKey  = 72;
  30. const unsigned char DnKey  = 80;
  31. const unsigned char Alt_S  = 31;  // The search key
  32. const unsigned char F1Key  = 59;  // The buffer switching key
  33. const unsigned char TabKey = 9;
  34. const unsigned char CR     = 10;  // Carriage return
  35.  
  36. struct Texel {                    // Structure used for
  37.   char Ch;                        // direct screen access
  38.   unsigned char Attr;             // Character attribute
  39. };
  40.  
  41. typedef Texel ScreenArea[25][80]; // The screen
  42.  
  43. // -------------------- The Screen Class --------------------- //
  44.  
  45. class ScreenClass {
  46. public:
  47.   ScreenArea far *ScreenPtr;
  48.   int ScrSize;
  49.   ScreenClass(unsigned Segment, unsigned Offset);
  50.   virtual ~ScreenClass(void) { ; }
  51.   char Get(int X, int Y) { return Screen[Y][X].Ch; }
  52.   void Put(int X, int Y, char Ch, unsigned char Atr);
  53.   void MarkLine(int Row, unsigned char Atr);
  54. };
  55.  
  56. // --------------------- The Buffer Class --------------------- //
  57.  
  58. class Buffer {
  59. public:
  60.   char *TextPtr, FileName[13];
  61.   unsigned char BuffAlloc;
  62.   int NoBytes, Attr, NumLines, LinePtr[2000];
  63.   long Size;
  64.   ftime Time;
  65.   ffblk ffblk;
  66.   FILE *fp;
  67.   Buffer(void);
  68.   virtual ~Buffer(void) { if (BuffAlloc) free(TextPtr); }
  69.   unsigned char OpenAndRead(char *FName);
  70.   void Dup(Buffer *Buf);
  71.   char GetCh(int Index);
  72.   virtual char *GetLine(char *Str, int Index);
  73.   virtual void SetLines(void);
  74.   int GetNumLines(void) { return NumLines; }
  75. };
  76.  
  77. // -------------------- The Hex Buffer Class ------------------ //
  78.  
  79. class HexBuffer : public Buffer {
  80. public:
  81.   HexBuffer(void): Buffer() { };
  82.   virtual char *GetLine(char *Str, int Index);
  83.   virtual void SetLines(void);
  84. };
  85.  
  86. // ----------------------- The Browser Class ------------------ //
  87.  
  88. class Browser {
  89. public:
  90.   ScreenClass *ScrPtr;
  91.   Buffer *MainBuff, *AltBuff;
  92.   int Lc, Bot, End;
  93.   Browser(ScreenClass *Scr, Buffer *Buf1, Buffer *Buf2);
  94.   virtual ~Browser(void) { ; }
  95.   void ProcessInput(char Ch);
  96.   void DisplayFStat(void);
  97.   void DisplayCommands(void);
  98.   void SetLPtr(void);
  99.   void ShowScreen(void);
  100.   void PageUp(void);
  101.   void PageDn(void);
  102.   void LineUp(void);
  103.   void LineDn(void);
  104.   void TopPage(void);
  105.   void BotPage(void);
  106.   void FileSearch(void);
  107. };
  108.  
  109. // Miscellaneous support functions
  110. char *GetStr(char *Str);
  111. char *ChToHex(char *Str, char Ch);
  112.  
  113. // ------------------- The Screen Member Functions ---------------- //
  114.  
  115. ScreenClass::ScreenClass(unsigned Segment, unsigned Offset)
  116. // Set up the pointer to video memory, and set the size of
  117. // the screen
  118. {
  119.   ScreenPtr = (ScreenArea *)(((long)Segment << 16) | (long)Offset);
  120.   ScrSize = 23;
  121. }
  122.  
  123. void ScreenClass::Put(int X, int Y, char Ch, unsigned char Atr)
  124. // Put a character to the screen at the given location
  125. {
  126.   Screen[Y][X].Ch = Ch;
  127.   Screen[Y][X].Attr = Atr;
  128. }
  129.  
  130. void ScreenClass::MarkLine(int Row, unsigned char Atr)
  131. // Highlight a line on the screen
  132. {
  133.   int Col;
  134.  
  135.   for (Col=0; Col<80; Col++) Screen[Row][Col].Attr = Atr;
  136. }
  137.  
  138. // ------------------- The Buffer Member Functions ---------------- //
  139.  
  140. Buffer::Buffer(void)
  141. // At the beginning, no buffer is allocated
  142. {
  143.   BuffAlloc = 0;
  144.   strcpy(FileName,"");
  145. }
  146.  
  147. char Buffer::GetCh(int Index)
  148. // Returns the specified character from the file buffer if
  149. // the index is in range. If the index is out of range, a
  150. // Control-Z (0x1A) is returned.
  151. {
  152.   return (Index < NoBytes) ? TextPtr[Index] : 0x1A;
  153. }
  154.  
  155. unsigned char Buffer::OpenAndRead(char *Fname)
  156. // Return true if the file Fname is opened and the file data
  157. // is read okay
  158. {
  159.   int DosError;
  160.  
  161.   DosError = findfirst(Fname, &ffblk, 0);
  162.   if (DosError != 0) {
  163.     printf("Can't find file %s\n", Fname);
  164.     return 0;
  165.   }
  166.   else {
  167.     if ((fp=fopen(Fname, "r")) == NULL) {  // Open file
  168.       printf("The file %s cannot be opened\n", Fname);
  169.       return 0;
  170.     }
  171.     else {
  172.       // Allocate buffer memory
  173.       // CODE CHANGE: Cannot cast to far * if in small memory model
  174.       if ((TextPtr=(char *)malloc(ffblk.ff_fsize)) == NULL) {
  175.         printf("Out of memory\n");
  176.         BuffAlloc = 0;
  177.         return 0;
  178.       }
  179.       else {
  180.         BuffAlloc = 1;          // Set flag noting allocation
  181.         // Read file data into buffer
  182.         getftime(fileno(fp), &Time);
  183.         Size = ffblk.ff_fsize;
  184.         if (Size >= MaxBufSize) {
  185.           printf("File is too large\n");
  186.           fclose(fp);
  187.           return 0;
  188.         }
  189.         else {
  190.           NoBytes = read(fileno(fp), TextPtr, ffblk.ff_fsize);
  191.           strcpy(FileName, Fname); // Record the file name
  192.           fclose(fp);              // Close the file
  193.           return 1;                // Read operation okay
  194.         }
  195.       }
  196.     }
  197.   }
  198. }
  199.  
  200. void Buffer::Dup(Buffer *Buf)
  201. // Duplicate another file buffer. The file attributes are
  202. // copied, but the file text is not. Instead, we merely point
  203. // to the text. Since we're not allocating the text buffer,
  204. // we make sure BuffAlloc is False (0). We'll change the line
  205. // pointer array, because we might not display lines the same
  206. // way with this new buffer.
  207. {
  208.   TextPtr   = Buf->TextPtr;  // Copy pointers only
  209.   NoBytes   = Buf->NoBytes;  // Copy file attributes
  210.   Size      = Buf->Size;
  211.   Time      = Buf->Time;
  212.   BuffAlloc = 0;             // Important to do this!
  213.   SetLines();                // Recompute line pointers
  214. }
  215.  
  216. char *Buffer::GetLine(char *Str, int Index)
  217. // Get the specified line from the buffer and return it in a
  218. // string.
  219. {
  220.   char Ch;
  221.   int P=0, I;
  222.  
  223.   while ((Ch=GetCh(Index)) != CR && Ch != 0x1A) {
  224.     if (Ch == TabKey)        // Look for tab
  225.       for (I=0; I<TabSize; I++)
  226.         Str[P++] = ' ';
  227.     else Str[P++] = Ch;
  228.     Index++;
  229.   }
  230.   Str[P] = '\0';             // Terminate string
  231.   return Str;
  232. }
  233.  
  234. void Buffer::SetLines(void)
  235. // Scan the text for newlines and set the line pointer array
  236. {
  237.   char Ch;
  238.   int L=0, I;
  239.  
  240.   LinePtr[L++] = 0;          // Initialize the index array
  241.   for (I=0; I<NoBytes; I++)
  242.     if ((Ch=GetCh(I)) == CR) LinePtr[L++] = I + 1;
  243.   NumLines = L;
  244. }
  245.                          
  246. // --------------- The Hex Buffer Member Functions -------------- //
  247.  
  248. char *HexBuffer::GetLine(char *Str, int Index)
  249. // Get the specified line from the buffer, returning both hex
  250. // and ASCII representations.
  251. {
  252.   char S[3] = "  ";
  253.   int I;
  254.  
  255.   strcpy(Str, "");
  256.   for (I=0; I<16; I++) {
  257.     strcat(Str, ChToHex(S, GetCh(Index+I)));
  258.     strcat(Str, " ");
  259.   }
  260.   strcat(Str, "| ");
  261.   for (I=0; I<16; I++) Str[I+50] = GetCh(Index+I);
  262.   Str[66] = '\0';
  263.   return Str;
  264. }
  265.  
  266. void HexBuffer::SetLines(void)
  267. // Set the line pointer array so that each line will point to
  268. // sixteen characters
  269. {
  270.   int L, I;
  271.  
  272.   NumLines = Size / 16;
  273.   if (Size % 16 != 0) NumLines++;
  274.   for (I=0, L=0; I<NumLines; I++, L+=16)
  275.     LinePtr[I] = L;
  276. }
  277.  
  278. // ------------------ The Browser Member Functions ---------------- //
  279.  
  280. Browser::Browser(ScreenClass *Scr, Buffer *Buf1, Buffer *Buf2)
  281. // Initialize the browser by setting up pointers to the
  282. // screen and to the two buffers
  283. {
  284.   ScrPtr = Scr;  MainBuff = Buf1;  AltBuff = Buf2;
  285. }
  286.  
  287. void Browser::DisplayFStat(void)
  288. // Display the first status line of file information
  289. // including file name, size, date, and time
  290. {
  291.    char AtStr[8];
  292.  
  293. // CODE CHANGE: The following lines don't do any good
  294. //              (see last line of function instead)
  295. //  int Col;
  296. //  for (Col=0; Col<80; Col++) // Put status bar in reverse video
  297. //    ScrPtr->Put(Col, 0, ' ', 112);
  298. //  textbackground(7);         // Text is set to black on white
  299. //  textcolor(0);
  300.  
  301.   gotoxy(3, 1);              // Display filename
  302.   printf("File: %s", MainBuff->FileName);
  303.   gotoxy(26, 1);
  304.   printf("Date: %02u-%02u-%04u", MainBuff->Time.ft_month,
  305.          MainBuff->Time.ft_day, MainBuff->Time.ft_year+1980);
  306.   gotoxy(48, 1);
  307.   printf("Size: %ld", MainBuff->Size); // Display size
  308.   // Display attributes
  309.   if (MainBuff->ffblk.ff_attrib == FA_RDONLY)
  310.     strcpy(AtStr, "R");
  311.   else strcpy(AtStr, "R-W");
  312.   if (MainBuff->ffblk.ff_attrib == FA_HIDDEN)
  313.     strcat(AtStr, "-H");
  314.   if (MainBuff->ffblk.ff_attrib == FA_SYSTEM)
  315.     strcat(AtStr, "-S");
  316.   gotoxy(63, 1);
  317.   printf("Attr: %s", AtStr);
  318.  
  319.   // CODE CHANGE: Added this line
  320.   ScrPtr->MarkLine(0, 112);
  321. }
  322.  
  323. void Browser::DisplayCommands(void)
  324. // Display the command bar at the last line of the screen
  325. {
  326. // CODE CHANGE: These lines do no good. See last line instead
  327. //  int Col;
  328. //  for (Col=0; Col<80; Col++) ScrPtr->Put(Col, 24, ' ', 112);
  329.   gotoxy(1, 25);
  330.   printf("<Home=Top> <End=Bot> <PgUp=Prv> <PgDn=Next> "
  331.           "<Alt-S=Search> <Esc=Quit> <F1=Flip>");
  332. // CODE CHANGE: Added this line
  333.   ScrPtr->MarkLine(24, 112);
  334. }
  335.  
  336. void Browser::SetLPtr(void)
  337. // Set the current and bottom line indices for the screen
  338. {
  339.   Lc = MainBuff->GetNumLines();
  340.   if (Lc > ScrPtr->ScrSize)   // Set the bottom line index
  341.     Bot = Lc - ScrPtr->ScrSize;
  342.   else Bot = 0;
  343.   End = Lc - 1;
  344.   Lc = 0;                     // Set the top line index
  345. }
  346.  
  347. void Browser::ShowScreen(void)
  348. // Displays a screen image containing 23 lines of the file
  349. {
  350.   int Row, Col, P, TLc, Length;
  351.   char Str[81];
  352.  
  353.   TLc = Lc; // Start with the current line index
  354.   for (Row=0; Row<ScrPtr->ScrSize && Row<=End; Row++) {
  355.     P = MainBuff->LinePtr[TLc];
  356.     strcpy(Str, MainBuff->GetLine(Str, P));
  357.     Length = strlen(Str);
  358.     for (Col=0; Col<80 && Col<Length; Col++)
  359.       ScrPtr->Put(Col, Row+1, Str[Col], 7);
  360.     for (; Col<80; Col++)
  361.       ScrPtr->Put(Col, Row+1, ' ', 7);
  362.     TLc++;
  363.   }
  364.   for (; Row<ScrPtr->ScrSize; Row++)
  365.     for (Col=0; Col<80; Col++)
  366.       ScrPtr->Put(Col, Row+1, ' ', 7);
  367. }
  368.  
  369. void Browser::PageUp(void)
  370. {
  371.   if (Lc-ScrPtr->ScrSize > 0) Lc -= ScrPtr->ScrSize;
  372.     else Lc = 0;
  373.   ShowScreen();
  374. }
  375.  
  376. void Browser::PageDn(void)
  377. {
  378.   if (Lc+ScrPtr->ScrSize < Bot && Bot >= ScrPtr->ScrSize)
  379.     Lc += ScrPtr->ScrSize;
  380.   else Lc = Bot;
  381.   ShowScreen();
  382. }
  383.  
  384. void Browser::LineUp(void)
  385. {
  386.   if (Lc > 0) {
  387.     Lc--;  ShowScreen();
  388.   }
  389. }
  390.  
  391. void Browser::LineDn(void)
  392. {
  393.   if (Lc < Bot && Bot >= ScrPtr->ScrSize) {
  394.     Lc++;  ShowScreen();
  395.   }
  396. }
  397.  
  398. void Browser::TopPage(void)
  399. {
  400.   Lc = 0;  ShowScreen();
  401. }
  402.  
  403. void Browser::BotPage(void)
  404. {
  405.   if (Bot >= ScrPtr->ScrSize) {
  406.     Lc = Bot;  ShowScreen();
  407.   }
  408. }
  409.  
  410. void Browser::FileSearch(void)
  411. // Searches the buffer for a string. If a match is found, the
  412. // line containing the string is highlighted.
  413. {
  414.   int Col, I, P;
  415.   char SearchStr[81], *S, Line[81], *Ptr;
  416.  
  417.   for (Col=0; Col<=78; Col++)
  418.     ScrPtr->Put(Col, 24, ' ', 112);
  419.   gotoxy(2, 25);
  420.   printf("Search for: ");
  421.   if ((S=GetStr(SearchStr)) == NULL) {   // Get the search string
  422.     DisplayCommands();
  423.     return;
  424.   }
  425.   I = Lc;
  426.   do {
  427.     P = MainBuff->LinePtr[I];
  428.     Col = 0;
  429.     strcpy(Line, MainBuff->GetLine(Line, P));
  430.     Ptr = strstr(Line, S);     // Look for a match
  431.     I++;
  432.   } while (Ptr == NULL && I <= End);
  433.  
  434.   if (Ptr != NULL) {             // Match found
  435.     if (I > Lc + ScrPtr->ScrSize) {
  436.       Lc = I - ScrPtr->ScrSize;
  437.       ShowScreen();
  438.     }
  439.     ScrPtr->MarkLine(I-Lc, 112);  // Highlight line with match
  440.     if (getch() == 0) (void)getch();
  441.     ScrPtr->MarkLine(I-Lc, 7);    // Set line back to normal
  442.   }
  443.   DisplayCommands();
  444. }
  445.  
  446. void Browser::ProcessInput(char Ch)
  447. {
  448.   Buffer *TempBuff;
  449.  
  450.   switch (Ch) {
  451.     case PgUp  : PageUp();  break;
  452.     case PgDn  : PageDn();  break;
  453.     case UpKey : LineUp();  break;
  454.     case DnKey : LineDn();  break;
  455.     case Home  : TopPage(); break;
  456.     case EndKey: BotPage(); break;
  457.     case F1Key :  // Toggle between the two types of buffers
  458.       TempBuff = MainBuff;
  459.       MainBuff = AltBuff;
  460.       AltBuff  = TempBuff;
  461.       SetLPtr();    // Reset top and bottom line indices
  462.          ShowScreen(); // Redisplay the screen
  463.       break;
  464.     case Alt_S : FileSearch(); break;
  465.   }
  466. }
  467.  
  468. // ------------------ Other supporting routines --------------- //
  469.  
  470. unsigned SelectMonitor(void)
  471. // Determine the type of monitor installed and return the
  472. // memory address of the installed monitor
  473. // CODE CHANGE: This function need only return an unsigned value
  474. {
  475.   struct REGS Regs;
  476.  
  477.   Regs.h.ah = 15;
  478.   int86(0x10, &Regs, &Regs);
  479.   if (Regs.h.al == 7) return 0xB000;  // Monochrome
  480.     else return 0xB800;               // Graphics
  481. }
  482.  
  483. char *GetStr(char *Str)
  484. // Read a string at the current cursor location
  485. {
  486.   char Ch;
  487.   int Count=0;
  488.  
  489.   while ((Ch=getch()) != 13 && Ch != EscKey) {
  490.      printf("%c", Ch);
  491.     Str[Count++] = Ch;
  492.   }
  493.   if (Ch == EscKey) return NULL;
  494.   Str[Count] = '\0';                 // Terminate string
  495.   return Str;
  496. }
  497.  
  498. char *ChToHex(char *Str, char Ch)
  499. // A support function for HexBuffer than converts a byte into
  500. // two hex digits
  501. {
  502.   const char HexDigits[17] = "0123456789ABCDEF";
  503.  
  504.   strncpy(Str, &HexDigits[Ch >> 4], 1);    // Create a two character
  505.   strncpy(&Str[1], &HexDigits[Ch & 0x0F], 1);  // string
  506.   return Str;
  507. }
  508.  
  509. // ------------------------- Main Program -------------------- //
  510.  
  511. main(int argc, char *argv[])
  512. {
  513.   char Ch;
  514.   ScreenClass *ScreenObj;
  515.   Browser *BrowseObj;
  516.   Buffer *BufObj;
  517.   HexBuffer *HexBufObj;
  518.  
  519.   clrscr();
  520.   if (argc != 2) {
  521.     printf("Incorrect number of arguments.\n");
  522.     printf("To browse a file use the command:\n");
  523.     printf("\tbrowse2 <filename>\n");
  524.     exit(1);
  525.   }
  526.  
  527.   if (!(ScreenObj = new ScreenClass(SelectMonitor(), 0x00))) {
  528.     printf("Not enough memory\n");
  529.     exit(1);
  530.   }
  531.   // Allocate and initialize buffer, read in data. If error
  532.   // reading data, quit.
  533.   if (!(BufObj = new Buffer())) {
  534.     printf("Not enough memory\n");
  535.     exit(1);
  536.   }
  537.   if (!BufObj->OpenAndRead(argv[1])) exit(1);
  538.   BufObj->SetLines();
  539.  
  540.   // Make hex buffer that duplicates what's in the other buffer
  541.   if (!(HexBufObj = new HexBuffer())) {
  542.     printf("Not enough memory\n");
  543.     exit(1);
  544.   }
  545.   HexBufObj->Dup(BufObj);
  546.  
  547.   // Now set up the browser to use the screen and buffer objects
  548.   if (!(BrowseObj = new Browser(ScreenObj, BufObj, HexBufObj))) {
  549.     printf("Not enough memory\n");
  550.     exit(1);
  551.   }
  552.  
  553.   // Draw browser screen, show initial lines
  554.  
  555.   BrowseObj->DisplayFStat();
  556.   BrowseObj->DisplayCommands();
  557.   BrowseObj->SetLPtr();
  558.   BrowseObj->ShowScreen();
  559.  
  560.   do {    // Process keys until Esc key pressed
  561.     Ch = getch();
  562.     switch (Ch) {
  563.          case 0:              // Extended key pressed
  564.         Ch = getch();
  565.         BrowseObj->ProcessInput(Ch);
  566.         break;
  567.          case EscKey: break;
  568.       default: putch(7);   // Illegal key, so sound the bell
  569.     }
  570.   } while (Ch != EscKey);
  571.  
  572.   delete BrowseObj;        // Remove objects
  573.   delete BufObj;
  574.   delete HexBufObj;
  575.   delete ScreenObj;
  576.  
  577.   textbackground(0);       // Restore screen back to normal
  578.   textcolor(7);
  579.   clrscr();
  580. }
  581.  
  582.